//
// Created by udi on 2020/8/4.
//

#include "interface.h"
#include "ipc/ipcInterface.h"

#define TAG    "jniCamera" // 这个是自定义的LOG的标识

_BEGIN

static JavaVM *g_JavaVM;
static jobject g_jinstance;
static jmethodID g_cameraRecvEventID;

#define MAX_CACHE_SIZE (1 * 1024 * 1024)
static unsigned char g_cacheH264Data[MAX_CACHE_SIZE];
static int g_cacheH264CurDataSize = 0;

void cameraRecvCallback(unsigned char *data, const int data_size, const unsigned int time_stamp, const unsigned int channelIndex, void *context);


JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
    g_JavaVM = vm;
    return JNI_VERSION_1_4;
}

JNIEXPORT void JNI_OnUnload(JavaVM *vm, void *reserved) {
    LOGD("JNI_OnUnload");
}


jlong JNICALL Java_com_zeng_incast_videoplay_live_camera_cameraInit(JNIEnv *env, jobject thiz, jstring url, jstring user, jstring passwd, jint channelIndex) {
    jclass  objectClass = env->GetObjectClass(thiz);
    g_cameraRecvEventID = env->GetMethodID(objectClass, "recvEvent", "([BIII)V");

    char* urlc = const_cast<char *>(env->GetStringUTFChars(url, NULL));
    char* userc = const_cast<char *>(env->GetStringUTFChars(user, NULL));
    char* passwdc = const_cast<char *>(env->GetStringUTFChars(passwd, NULL));
    const unsigned int channelIndexui = (const unsigned int)channelIndex;
    const IPCameraRecvCallBackFunc callback = reinterpret_cast<IPCameraRecvCallBackFunc const>(cameraRecvCallback);

    jmethodID classConstructor = env->GetMethodID(objectClass, "<init>", "()V");
    jobject ttp = env->NewObject(objectClass, classConstructor);
    g_jinstance = env->NewGlobalRef(ttp);

    void* camera = ip_camera_init(urlc, userc, passwdc, callback, NULL, channelIndexui);
    long jcamera = (long) camera;

    env->ReleaseStringUTFChars(url, urlc);
    env->ReleaseStringUTFChars(user, userc);
    env->ReleaseStringUTFChars(passwd, passwdc);

    return jcamera;
}

jint JNICALL Java_com_zeng_incast_videoplay_live_camera_cameraExit(JNIEnv *env, jobject thiz, jlong jobj) {
    void *camera = (void *) jobj;
    if (!camera) {
        return -1;
    }

    ip_camera_exit(camera);
    return 0;
}


void cameraRecvCallback(unsigned char *data, const int data_size, const unsigned int time_stamp, const unsigned int channelIndex, void *context) {
    unsigned char sign = data[4] & 0x1F;
    if(data_size <64 && (sign == 0x07 || sign == 0x08 || sign == 0x06)) {
        memcpy(&g_cacheH264Data[g_cacheH264CurDataSize], data, data_size);
        g_cacheH264CurDataSize += data_size;
        return;
    }

    unsigned char* out = data;
    int outSize = data_size;
    if(g_cacheH264CurDataSize > 0 && sign == 0x05) {
        memcpy(&g_cacheH264Data[g_cacheH264CurDataSize], data, data_size);
        g_cacheH264CurDataSize += data_size;

        out = g_cacheH264Data;
        outSize = g_cacheH264CurDataSize;

        g_cacheH264CurDataSize = 0;
    }

    JNIEnv *jni = NULL;
    g_JavaVM->AttachCurrentThread(&jni, 0);
    jbyteArray pSend = jni->NewByteArray(outSize);
    jni->SetByteArrayRegion(pSend, 0, outSize, reinterpret_cast<const jbyte *>(out));

    jni->CallVoidMethod(g_jinstance, g_cameraRecvEventID, pSend, outSize, static_cast<int>(time_stamp), static_cast<int>(channelIndex));

    jni->ReleaseByteArrayElements(pSend, jni->GetByteArrayElements(pSend, NULL), 0);
    g_JavaVM->DetachCurrentThread();
}

_END